package com.eu.ebpm.engine.deploy;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.Element;

import com.eu.ebpm.engine.entity.deploy.Deploy;
import com.eu.ebpm.engine.entity.deploy.Mission;
import com.eu.ebpm.engine.entity.deploy.Position;
import com.eu.ebpm.engine.entity.deploy.Transfer;
import com.eu.ebpm.engine.pvm.EngineServiceType;
import com.eu.ebpm.engine.util.XmlUtil;

/**
 * @author wxh
 */
public class XmlDefine {
	
	//流程部署基本信息
	private List<Deploy> deploys = new ArrayList<Deploy>();
	private List<Mission> missions = new ArrayList<Mission>();
	private List<Transfer> transfers = new ArrayList<Transfer>();
	private List<Position> positions = new ArrayList<Position>();
	
	//xml流程定义内容
	private String xmlContent;
	private String taskJson;
	private String lineJson;
	
	//流程【根deploy信息】
	private Deploy rootDeploy;
	
	//开始节点
	private 	Mission startEvent;
	
	//流程定义所有节点信息
	private List<Element> definitionsElements;
	
	//所有mission节点
	private 	Map<String, Mission> missionMap = new HashMap<String, Mission>();
	
	//key --> missionName ; list<Mission> --> targetRefMissions  节点指向出去的对应节点
	private 	Map<String, List<Mission>> sourceRefMission2TargetRefMissionMap = new HashMap<String, List<Mission>>();
	
	//是否递归过的mission
	private 	Map<String, Boolean> isRecursion = new HashMap<String, Boolean>();
	
	//子流程的父节点的parentDeployId
	private 	Map<String, Long> subStartEventParentDeployIdMap = new HashMap<String, Long>();
	
	//子流程[结束节点]与子流程[开始节点]映射关系
	private Map<String, String> subEndEvent2SubStartEventMap = new HashMap<String, String>();
	
	//子流程开始节点
	private List<String> subStartEventIds = new ArrayList<String>();
	
	/**
	 * @param xmlContent 流程定义xml内容
	 * @return 【deploys】【missions】【transfers】【positions】
	 */
	public XmlDefine(String xmlContent) {
		
		this.xmlContent =  xmlContent;
		
		//解析【根流程】
		parserRootDeploy();
		
		//解析mission信息
		parserMission(rootDeploy, definitionsElements);
		
		//解析mission的位置信息
		parserPosition();
		
		//解析transfer信息
		parserTransfer(definitionsElements);
		
		//递归设置mission的deployId
		recursionSetDeployId(startEvent, rootDeploy.getId(), (long) 0);
		
	}

	@SuppressWarnings("unchecked")
	private void parserRootDeploy() {
		
		String definitionsXml = xmlContent.substring(0, xmlContent.indexOf("<Position>"));
		
		taskJson = xmlContent.substring(xmlContent.indexOf("<TaskJson>"), xmlContent.indexOf("<LineJson>"));
		taskJson = XmlUtil.getDocument(new StringReader(taskJson)).getRootElement().getText().trim();
		
		lineJson = xmlContent.substring(xmlContent.indexOf("<LineJson>"), xmlContent.length());
		lineJson = XmlUtil.getDocument(new StringReader(lineJson)).getRootElement().getText().trim();
		
		Document defineDocument = XmlUtil.getDocument(new StringReader(definitionsXml));
		
		Element root = defineDocument.getRootElement();
		
		//初始化流程信息
		rootDeploy = new Deploy(root.attributeValue("key"), root.attributeValue("key"), root.attributeValue("desc"), 0, new Date(), 0, 0L, this.xmlContent, (this.taskJson + "$$" + this.lineJson));
		rootDeploy.setRootId(rootDeploy.getId());
		deploys.add(rootDeploy);
		
		definitionsElements = root.elements();
	}

	private void parserTransfer(List<Element> list) {
		
		for(Element mission : list) {
			if(mission.getName().equals("SequenceFlow")) {
				
				Transfer t = new Transfer(mission.attributeValue("id"), mission.attributeValue("desc"), missionMap.get(mission.attributeValue("sourceRef")).getId(), missionMap.get(mission.attributeValue("targetRef")).getId(), mission.element("Express").getText());
				
				t.setFromMission(missionMap.get(mission.attributeValue("sourceRef")));
				t.setToMission(missionMap.get(mission.attributeValue("targetRef")));
				
				List<Mission> listTarget = sourceRefMission2TargetRefMissionMap.get(mission.attributeValue("sourceRef"));
				if(listTarget == null) {
					listTarget = new ArrayList<Mission>();
				}
				listTarget.add(missionMap.get(mission.attributeValue("targetRef")));
				sourceRefMission2TargetRefMissionMap.put(mission.attributeValue("sourceRef"), listTarget);
				
				transfers.add(t);
			}
		}
		
		for(String subStartEvent : subStartEventIds) {
			findSubEndBySubStart(subStartEvent, subStartEvent);
		}
		
	}

	private void parserMission(Deploy rootDeploy, List<Element> listNode) {
		
		for(Element missionNode : listNode) {
			
			//如果是mission节点
			if(!missionNode.getName().equals("SequenceFlow")) {
				
				Mission mission = new Mission(0, missionNode.attributeValue("id"), missionNode.attributeValue("name"), missionNode.attributeValue("candidateUsers"), missionNode.attributeValue("candidateGroups"), missionNode.attributeValue("candidateOrgs"), missionNode.attributeValue("assignee"), missionNode.attributeValue("taskFilter"), missionNode.attributeValue("serviceTaskExecute"), EngineServiceType.getType(missionNode.getName()));
				
				if(missionNode.getName().equals("StartEvent")) {
					mission.setDeployId(rootDeploy.getId());
					startEvent = mission;
				}
				
				if(missionNode.getName().equals("SubStartEvent")) {
					mission.setSubKey(missionNode.attributeValue("subKey"));
					mission.setSubDesc(missionNode.attributeValue("subDesc"));
					subStartEventIds.add(missionNode.attributeValue("id"));
				}
				
				missionMap.put(mission.getName(), mission);
				isRecursion.put(mission.getName(), true);
			}
			
		}
		
	}
	
	@SuppressWarnings("unchecked")
	private void parserPosition() {
		
		String positionXmlContent = xmlContent.substring(xmlContent.indexOf("<Position>"), xmlContent.indexOf("<TaskJson>"));
		Document positionDocument = XmlUtil.getDocument(new StringReader(positionXmlContent));
		Element positionRootNode = positionDocument.getRootElement();
		
		List<Element> listNode = positionRootNode.elements();
		for(Element pNode : listNode) {
			if(!pNode.getName().equals("SequenceFlow")) {
				Position position = new Position();
				position.setW(Integer.parseInt(pNode.attributeValue("w")));
				position.setH(Integer.parseInt(pNode.attributeValue("h")));
				position.setX(Integer.parseInt(pNode.attributeValue("x")));
				position.setY(Integer.parseInt(pNode.attributeValue("y")));
				position.setMissionId(missionMap.get(pNode.attributeValue("id")).getId());
				positions.add(position);
			}
		}
		
	}

	/**
	 * 根据子流程开始节点【SubStartEvent】递归查询子流程结束节点【SubEndEvent】
	 * 	1、子流程里面【不允许只嵌套】子流程
	 * 	2、否则该方法找不到子流程的结束节点
	 * 	3、该方法依赖sourceRefMission2TargetRefMissionMap的初始化
	 */
	public boolean findSubEndBySubStart(String subStartEvent, String sourceRefMission) {
		
		List<Mission> targetRefMissionList = sourceRefMission2TargetRefMissionMap.get(sourceRefMission);
		
		if(targetRefMissionList != null) {
			
			for(Mission targetRefMission : targetRefMissionList) {
				if(targetRefMission.getType() == EngineServiceType.SUB_START_EVENT) continue ;
				if(targetRefMission.getType() == EngineServiceType.SUB_END_EVENT) {
					subEndEvent2SubStartEventMap.put(targetRefMission.getName(), subStartEvent);
					return true;
				}
				if(findSubEndBySubStart(subStartEvent, targetRefMission.getName())) return true;
			}
			
		}
		
		return false;
	}

	private void recursionSetDeployId(Mission mission, long deployId, long parentDeployId) {
		
		if(mission.getType() == EngineServiceType.SUB_START_EVENT) {
			
			//如果是子流程,添加子流程deploy的信息
			Deploy deploy = new Deploy(mission.getSubKey(),mission.getSubKey(), mission.getSubDesc(), 0, new Date(), deployId, rootDeploy.getId(), this.xmlContent, (this.taskJson + "$$" + this.lineJson));
			deploys.add(deploy);
			
			//记录SubStartEvent的父流程的parentDeployId
			subStartEventParentDeployIdMap.put(mission.getName(), parentDeployId);
			
			parentDeployId = deployId;
			
			deployId = deploy.getId();
		} 
		
		//设置deployId
		mission.setDeployId(deployId);
		//添加mission
		missions.add(mission);
		
		List<Mission> targetRefMissionList = sourceRefMission2TargetRefMissionMap.get(mission.getName());
		
		if(targetRefMissionList != null) {
			
			//1、如果是【SubEndEvent】则需要将deployId 回退为parentDeployId
			//2、找出【SubStartEvent】的parentDeployId，重新设置
			if(mission.getType() == EngineServiceType.SUB_END_EVENT) {
				deployId = parentDeployId;
				String subStartEvent = subEndEvent2SubStartEventMap.get(mission.getName());
				parentDeployId = subStartEventParentDeployIdMap.get(subStartEvent);
			}
			
			for(Mission targetRefMission : targetRefMissionList) {
				if(isRecursion.get(targetRefMission.getName())) {
					isRecursion.put(targetRefMission.getName(), false);
					recursionSetDeployId(targetRefMission, deployId, parentDeployId);
				}
			}
			
		}
		
	}

	public List<Deploy> getDeploys() {
		return deploys;
	}

	public List<Mission> getMissions() {
		return missions;
	}

	public List<Transfer> getTransfers() {
		return transfers;
	}

	public List<Position> getPositions() {
		return positions;
	}

	public Deploy getRootDeploy() {
		return rootDeploy;
	}
	
	public static String getDrawItem(String xmlContent) {
		String taskJson = xmlContent.substring(xmlContent.indexOf("<TaskJson>"), xmlContent.indexOf("<LineJson>"));
		taskJson = XmlUtil.getDocument(new StringReader(taskJson)).getRootElement().getText().trim();
		
		String lineJson = xmlContent.substring(xmlContent.indexOf("<LineJson>"), xmlContent.length());
		lineJson = XmlUtil.getDocument(new StringReader(lineJson)).getRootElement().getText().trim();
		
		return taskJson + "$$" + lineJson;
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	

}
